package cn.gcyl.module.biz.enums.sender;

import cn.gcyl.framework.common.util.json.JsonUtils;
import cn.gcyl.module.biz.dal.dataobject.thirdpartyinformation.ThirdPartyInformationDO;
import cn.gcyl.module.biz.service.thirdpartyinformation.ThirdPartyInformationService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 第三方信息定时获取任务
 */
@Component
@Slf4j
public class ThirdPartyInformationSender {

    @Resource
    private ThirdPartyInformationService thirdPartyInformationService;

    private static final String TOKEN_URL = "https://sso.yjsc.com.cn/oauth/token";
    private static final String INFO_URL = "https://www.chinabidding.cn/302e302e7379675f73736f/datax/json/gcxh_search_info";

    private RestTemplate restTemplate = new RestTemplate();

    /**
     * 每天凌晨0点执行定时任务
     */
    @Scheduled(cron = "0 0 0 * * ?")
    public void fetchAndSaveThirdPartyInfo() {
        log.info("开始执行第三方信息获取任务，时间: {}", LocalDateTime.now());
        try {
            // 1. 获取access_token
            String accessToken = getAccessToken();
            if (accessToken == null || accessToken.isEmpty()) {
                log.error("获取access_token失败");
                return;
            }
            log.info("成功获取access_token");
            // 2. 获取各类信息并保存
            String[] infoTypes = {"招标", "中标", "采购"};
            for (String infoType : infoTypes) {
                fetchAndSaveInfoByType(accessToken, infoType);
            }
            log.info("第三方信息获取任务执行完成");
        } catch (Exception e) {
            log.error("执行第三方信息获取任务时发生异常", e);
        }
    }

    /**
     * 获取access_token
     * @return access_token
     */
    private String getAccessToken() {
        try {
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.MULTIPART_FORM_DATA);

            // 构建表单数据
            MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
            formData.add("grant_type", "password");
            formData.add("client_id", "gcxh_1753688509");
            formData.add("client_secret", "c911ce6175c2e32c7b0beac6875950ff");
            formData.add("username", "gcxh@chinabidding.cn");
            formData.add("password", "2xcmflzK");
            formData.add("scope", "*");
            formData.add("corpid", "_@V4HKbOp4n8rVzCKRGy4Y06qNT36ORzXO@");
            HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(formData, headers);

            ResponseEntity<Map> response = restTemplate.postForEntity(TOKEN_URL, request, Map.class);

            if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) {
                Map<String, Object> responseBody = response.getBody();
                log.debug("获取access_token完整响应: {}", responseBody);

                // 根据API文档，access_token在data对象中
                if (responseBody.containsKey("data")) {
                    Map<String, Object> data = (Map<String, Object>) responseBody.get("data");
                    if (data.containsKey("access_token")) {
                        String accessToken = (String) data.get("access_token");
                        log.info("成功获取access_token，长度: {}", accessToken != null ? accessToken.length() : 0);
                        return accessToken;
                    } else {
                        log.error("响应中缺少access_token字段，data: {}", data);
                    }
                } else {
                    log.error("响应中缺少data字段，响应内容: {}", responseBody);
                }
            } else {
                log.error("获取access_token HTTP请求失败，状态码: {}", response.getStatusCode());
            }
        } catch (Exception e) {
            log.error("获取access_token时发生异常", e);
        }
        return null;
    }
    /**
     * 根据信息类型获取并保存信息（获取前10页数据）
     * @param token access_token
     * @param infoType 信息类型
     */
    private void fetchAndSaveInfoByType(String token, String infoType) {
        try {
            log.info("开始获取{}信息", infoType);

            int page = 1;
            int size = 20;
            int maxPage = 10; // 固定获取10页
            int totalSaved = 0;
            int totalProcessed = 0;

            // 获取10页数据
            for (page = 1; page <= maxPage; page++) {
                log.info("获取{}信息，第{}/{}页", infoType, page, maxPage);

                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

                MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
                params.add("token", token);
                params.add("info_type", infoType);
                params.add("page", String.valueOf(page));
                params.add("size", String.valueOf(size));

                HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);

                ResponseEntity<String> response = restTemplate.postForEntity(INFO_URL, request, String.class);

                if (response.getStatusCode().is2xxSuccessful()) {
                    int processedCount = processAndSaveInfo(response.getBody(), infoType);

                    // 如果遇到错误，记录日志并继续处理下一页
                    if (processedCount == -1) {
                        log.warn("获取{}信息第{}页时遇到错误，继续处理下一页", infoType, page);
                        continue;
                    }

                    totalProcessed += processedCount;
                    // 只统计实际保存的数量
                    if (processedCount > 0) {
                        // 这里需要区分处理的数量和保存的数量
                        totalSaved += getSavedCountFromResponse(response.getBody());
                    }

                    log.info("完成处理第{}页数据，处理了{}条记录", page, processedCount);

                    // 添加短暂延迟，避免请求过于频繁
                    if (page < maxPage) { // 最后一页不需要延迟
                        try {
                            Thread.sleep(300); // 减少延迟时间
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            break;
                        }
                    }
                } else {
                    log.error("获取{}信息第{}页失败，HTTP状态码: {}", infoType, page, response.getStatusCode());
                }
            }

            log.info("获取{}信息完成，总共处理{}条数据，保存{}条数据", infoType, totalProcessed, totalSaved);
        } catch (Exception e) {
            log.error("获取{}信息时发生异常", infoType, e);
        }
    }

    /**
     * 从响应中获取实际保存的数据条数
     * @param jsonData JSON数据
     * @return 实际数据条数
     */
    @SuppressWarnings("unchecked")
    private int getSavedCountFromResponse(String jsonData) {
        try {
            Map<String, Object> responseMap = JsonUtils.parseObject(jsonData, Map.class);
            if (responseMap != null && responseMap.containsKey("code")) {
                Integer code = (Integer) responseMap.get("code");
                if (code == 200 && responseMap.containsKey("items")) {
                    Object itemsObj = responseMap.get("items");
                    if (itemsObj instanceof List) {
                        return ((List<?>) itemsObj).size();
                    }
                }
            }
        } catch (Exception e) {
            log.warn("解析响应数据条数时发生异常", e);
        }
        return 0;
    }

    /**
     * 处理并保存信息
     * @param jsonData JSON数据
     * @param infoType 信息类型
     * @return 处理的数据条数，-1表示遇到错误
     */
    @SuppressWarnings("unchecked")
    private int processAndSaveInfo(String jsonData, String infoType) {
        try {
            log.debug("处理{}信息的原始响应数据: {}", infoType, jsonData);

            Map<String, Object> responseMap = JsonUtils.parseObject(jsonData, Map.class);

            // 检查解析结果
            if (responseMap == null) {
                log.error("解析{}信息响应数据失败，返回null", infoType);
                return 0;
            }

            // 检查返回码（根据文档，成功时code为200）
            if (responseMap.containsKey("code")) {
                Object codeObj = responseMap.get("code");
                Integer code;
                if (codeObj instanceof Integer) {
                    code = (Integer) codeObj;
                } else if (codeObj instanceof String) {
                    try {
                        code = Integer.parseInt((String) codeObj);
                    } catch (NumberFormatException e) {
                        log.error("无法将code转换为整数，值: {}", codeObj);
                        return 0;
                    }
                } else {
                    log.error("code字段类型不支持，类型: {}, 值: {}", codeObj.getClass().getName(), codeObj);
                    return 0;
                }

                log.debug("获取{}信息返回码: {}", infoType, code);

                if (code == 200) {
                    if (responseMap.containsKey("items")) {
                        Object itemsObj = responseMap.get("items");
                        if (itemsObj instanceof List) {
                            List<Map<String, Object>> infoList = (List<Map<String, Object>>) itemsObj;

                            log.info("解析到{}条{}信息", infoList.size(), infoType);

                            int savedCount = 0;
                            for (Map<String, Object> info : infoList) {
                                // 检查是否已存在相同记录
                                // 使用返回数据中的id字段作为thirdPartyId进行去重
                                String thirdPartyId = getStringValue(info, "id");

                                if (thirdPartyId != null) {
                                    if (!isInfoExists(thirdPartyId)) {
                                        ThirdPartyInformationDO informationDO = ThirdPartyInformationDO.builder()
                                                .thirdPartyId(thirdPartyId) // 使用返回的id字段
                                                .title(getStringValue(info, "title"))
                                                .infoType(getStringValue(info, "info_type"))
                                                .category(getStringValue(info, "category"))
                                                .area(getStringValue(info, "area"))
                                                .publishDate(getStringValue(info, "publish_date"))
                                                .description(getStringValue(info, "description"))
                                                .build();

                                        try {
                                            thirdPartyInformationService.createThirdPartyInformation(informationDO);
                                            savedCount++;
                                            log.debug("保存信息成功: ID={}, 标题={}", thirdPartyId, getStringValue(info, "title"));
                                        } catch (Exception e) {
                                            log.error("保存信息失败: ID={}, 标题={}", thirdPartyId, getStringValue(info, "title"), e);
                                        }
                                    } else {
                                        log.debug("信息已存在，跳过: ID={}", thirdPartyId);
                                    }
                                } else {
                                    log.warn("信息缺少id字段，无法保存，信息内容: {}", info);
                                }
                            }

                            log.info("处理{}条{}信息，实际保存{}条", infoList.size(), infoType, savedCount);
                            return infoList.size(); // 返回处理的总条数
                        } else {
                            log.error("{}信息的items字段类型不正确，期望List，实际类型: {}", infoType, itemsObj.getClass().getName());
                        }
                    } else {
                        log.warn("获取{}信息成功但缺少items字段，响应内容: {}", infoType, responseMap);
                    }
                } else {
                    String msg = getStringValue(responseMap, "msg");
                    log.error("获取{}信息失败，错误码: {}，错误信息: {}", infoType, code, msg);
                    return -1;
                }
            } else {
                log.error("获取{}信息响应中缺少code字段，响应内容: {}", infoType, responseMap);
            }
        } catch (Exception e) {
            log.error("处理{}信息时发生异常，响应数据: {}", infoType, jsonData, e);
        }
        return 0;
    }



    /**
     * 检查信息是否已存在（通过thirdPartyId判断）
     * @param thirdPartyId 第三方ID
     * @return 是否存在
     */
    private boolean isInfoExists(String thirdPartyId) {
        try {
            // 使用thirdPartyId查询数据库判断是否已存在
            ThirdPartyInformationDO existingInfo = thirdPartyInformationService.getThirdPartyInformationByThirdPartyId(thirdPartyId);
            return existingInfo != null;
        } catch (Exception e) {
            log.warn("检查信息是否存在时发生异常，thirdPartyId: {}", thirdPartyId, e);
            // 出现异常时，默认认为不存在，避免数据丢失
            return false;
        }
    }

    /**
     * 安全获取字符串值
     * @param map Map对象
     * @param key 键
     * @return 字符串值
     */
    private String getStringValue(Map<String, Object> map, String key) {
        Object value = map.get(key);
        return value != null ? value.toString() : null;
    }
}